#include "connecter.h"
#include "QDebug"


/* @brief getChangedEndian: the point to the uint8_t array which store the data by Big-endian or small-endian
 *       and we will change the mode.
 * @param pSmallBit: the point to the uint8_t array which store the data in Big-endian or small-endian
 * @param bytes
 * @return The data that changed
 * @author
 */
uint64_t getChangedEndian(uint8_t* pSmallBit,uint8_t bytes)
{
    uint8_t temp[8] = {0,0,0,0,0,0,0,0};
    for(int j = 0;j < bytes;j++) // change the endian
    {
        temp[j] = pSmallBit[bytes - 1 - j];
    }
    return *(uint64_t*)temp;
}

namespace canCont {

/* @brief sumCheck:the 28 bytes sum check of frame
 *        in the connecter protocol the sumcheck don't need to reverse
 * @author
 */
void protocol::sumCheck()
{
    uint8_t* pdata = head;
    uint8_t sum = 0;
    for(int i = 0;i < 28;i++)
    {
        sum += pdata[i];
    }
    pdata[28] = sum;
}

/* @brief Initialize the parameter of frame
 */
SendParam::SendParam(){
    head[0] = 0X55;
    head[1] = 0XAA;
    func = 1;
    tail = 0X88;
    data[5] = 1;
    data[22] = 0X77;
    data[23] = 0x88;
    data[24] = 0X99;
}

/* @brief set the connecter work param
 * @param mode:normal....
 * @param tbs1:The number of sample interval before sample time
 * @param tbs2:The number of sample interval before sample time
 * @param brp: The STM32 single on chip hardware information,equal to the frequency divider
 */
void SendParam::setWorkMode(WorkMode mode, uint8_t tbs1, uint8_t tbs2, uint16_t brp)
{
    data[0] = mode;
    data[1] = tbs1;
    data[2] = tbs2;;
    data[3] = (brp & 0Xff00)>>8;
    data[4] = brp & 0x00ff;
    sumCheck();
}

/* @brief SendFilter:Initialize the parameter of the frame
 */
SendFilter::SendFilter()
{
    head[0] = 0X55;
    head[1] = 0XAA;
    func = 0X02;
    tail = 0X88;
}

/* @brief setFilter:set the filters in stm32 of the connecter
 * @param num: the serial number of the filter of stm32
 * @param open: open or close
 * @param id: the id of filter
 * @param mask: the mask of id
 * @author
 */
void SendFilter::setFilter(uint8_t num,bool open,uint32_t id,uint32_t mask){
    data[0] = num;
    data[1] = open;
    uint8_t* p0 = (uint8_t*)&id;
    uint8_t* p1 = (uint8_t*)&data[2];
    for(int i = 0;i < 4;i++)
    {
        p1[i] = p0[3 - i];  // 无法用英语描述:由于intel内核存储数据采用小端模式，但是CAN协议是大端在前，因此得反向
    }
    p0 = (uint8_t*)&mask;
    p1 = (uint8_t*)&data[6];
    for(int i = 0;i < 4;i++)
    {
        p1[i] = p0[3 - i];
    }
    sumCheck();
}

/* @brief Initial the parameter of send mailbox frame
 * @author
 */
SendMail::SendMail(){
    head[0] = 0X55;
    head[1] = 0XAA;
    func = 3;
    tail = 0X88;
}

/* @brief SetMailBox:set the mailbox register of stm32,which includes TIxR,TDxT,TDHR,TDLR,register
 * @param size:frame size type: Standard Expanded..
 * @param id: The id of device
 * @param type:The type of frame,such as data,remote..
 * @param dlc: The bytes of data
 * @param pData: the pointer to the data which should has the bytes bigger than dlc
 */
void SendMail::setMailBox(FrameSize size, uint32_t id, FrameType type, uint8_t dlc, uint8_t *pData)
{
    uint8_t* pu8ToData = data;
    id = id << 3;
    uint8_t* pu8Toid = (uint8_t*)&id;
    for(int i = 0;i < 4;i++){pu8ToData[i] = pu8Toid[3 - i];}  // change the endian
    // if the frame is a Expanded frame
    if(size == Expanded)pu8ToData[3] |= 1<<2;
    else pu8ToData[3] &= ~(1<<2);
    // if the frame is the remote frame
    if(type == TypeRequest)pu8ToData[3] |= 1<<1;
    else pu8ToData[3] &= ~(1<<1);

    pu8ToData[3] |= 1; // set the TXRQ

    pu8ToData += 4; // goto next 32 bit
    // set the dlc
    pu8ToData[3] = dlc;

    pu8ToData += 4;
    // set data
    for(int i = 0;i < dlc;i++)
    {
        pu8ToData[i] = pData[dlc - 1 - i];
    }
    sumCheck();

}

/* @brief ...
 * @author
 */
SendReset::SendReset()
{
    head[0] = 0X55;
    head[1] = 0XAA;
    func = 0X04;
    tail = 0X88;
    for(int i = 0;i < 25;i++)
    {
        data[i] = 0;
    }
    sumCheck();
}

/* @brief ...
 */
SendClear::SendClear()
{
    head[0] = 0X55;
    head[1] = 0XAA;
    func = 0X05;
    tail = 0X88;
    data[0] = 1;
    for(int i = 1;i < 25;i++)
    {
        data[i] = 0;
    }
    sumCheck();
}

/* @brief getInformation: Get the information from connect,contain the data in object.
 * @param data: The pointer to received data
 * @author
 */
std::vector<ReceInfo> ReceiveInformation::getInformation(uint8_t *data,uint32_t len)
{
    std::vector<ReceInfo> listInfo;
    protocol* p;
    uint8_t* p8;
    for(uint32_t i = 0;i < len - 1;)
    {
        if(data[i] == 0xAA && data[i + 1] == 0X55)
        { // when we find the frame head
            ReceInfo receive;
            p = (protocol*) &data[i];

            if(i + 30 > len)return listInfo;
            i += 29; // goto the next frame

            uint32_t sumcheck = p->data[24];        // do the sum check
            p->sumCheck();
            if(sumcheck != p->data[24])continue;

            if(p->tail != 0X88)continue;            // do the tail check
            if(p->func != 0X01 && p->func != 0X02)continue;       // do the function code check
            else if(p->func == 0X01)
            {// successful received function code 0x01
               receive.filterEnNum = p->data[0];
               receive.offLine = p->data[3];
               receive.errorRecent = p->data[4];
               receive.sendErrorNum = p->data[5];
               receive.receiveErrorNum = p->data[6];

               p8 = &(p->data[7]);
               receive.baudrate = getChangedEndian(p8,3);

               p8 = &(p->data[10]);
               receive.sendCount = getChangedEndian(p8,4);

               p8 = &(p->data[14]);
               receive.sendSucessCount = getChangedEndian(p8,4);

               p8 = &(p->data[14]);
               receive.sendSucessCount = getChangedEndian(p8,4);

               p8 = &(p->data[18]);
               receive.sendFailCount = getChangedEndian(p8,4);
            }
            else if(p->func == 0x02)
            {
                qDebug()<<"C";
                receive.receiveSuccessCount = getChangedEndian(&(p->data[0]),4);
                listInfo.push_back(receive);    // when the next fram with successcount received pushback
            }
        }
        i++;
    }
    return listInfo;
}

/* @brief ReceiveData: when the protocol func is 0x03,this frame is data frame
 *        this data where instore int four resgiters in stm32,that is FIFO mailbox register，
 *        which includes RIxR RDTxR RDLxR and RDHxR.more information are in stm32 datasheet
 *
 * @author
 */
std::vector<ReceData> ReceiveData::getData(uint8_t* data,uint32_t len)
{
    std::vector<ReceData> listReceived;
    uint8_t* p8;
    protocol* prot;
    for(uint32_t i = 0;i < len - 1;)
    {
        if(data[i] == 0xAA && data[i+1] == 0X55)    // frame head is finded
        {
            ReceData receive;
            prot = (protocol*)(&data[i]);
            if(i + 30 > len)return listReceived;
            i += 29;    // go to next frame;

            if(prot->func != 0x03)continue;

            if(prot->tail != 0X88)continue;   // frame tail code isn't matching

            uint32_t sumcheck = prot->data[24];        // do the sum check
            prot->sumCheck();
            if(sumcheck != prot->data[24])continue;

            p8 = (uint8_t*)&(prot->data[0]);
            uint32_t temp = getChangedEndian(p8,4);

            receive.ID = (temp & 0XFFFFFFF8)>>3;         // get the ID
            if(temp & (1 << 2))receive.size = Expanded;  // get the IDE
            else receive.size = Standard;
            if(temp & (1<<1))receive.type = TypeRequest; // get the RTR
            else receive.type = TypeData;
            receive.dataLen = prot->data[7] & 0X0F;      // get the data length
            if(receive.type == TypeData)
            {
                p8 = (uint8_t*)&(prot->data[8]);
                receive.frameData.dataInt[1] =  getChangedEndian(p8,4);     // put the 32 bits data in frameData
                p8 = (uint8_t*)&(prot->data[12]);
                receive.frameData.dataInt[0] =  getChangedEndian(p8,4);     // put the 32 bits data in frameData

            }
            receive.isSucess = true;
            listReceived.push_back(receive);

        }
        i++;
    }
    return listReceived;
}

/* @brief clearCount: send clear Frame to connecter
 *
 */
void CAN_Connecter::clearCount()
{
    char* head = (char*)sendClearFrame.head;
    serial.write(head,30);
}

/* @brief clearCount: send reset Frame to connecter
 *
 */
void CAN_Connecter::resetConnecter()
{
    char* head = (char*)sendResetFrame.head;
    serial.write(head,30);
}

/* @brief clearCount: send reset Frame to connecter
 *
 */
void CAN_Connecter::setParam(WorkMode mode, uint8_t tbs1, uint8_t tbs2, uint16_t brp)
{
    sendParamFrame.setWorkMode(mode,tbs1,tbs2,brp);
    char* head = (char*)sendParamFrame.head;
    serial.write(head,30);
}

/* @brief clearCount: send reset Frame to connecter
 *
 */
void CAN_Connecter::sendData(FrameSize size, uint32_t id, uint8_t dlc, uint8_t *pData)
{
    sendDataFrame.setMailBox(size,id,TypeData,dlc,pData);
    char* head = (char*)sendDataFrame.head;
    serial.write(head,30);
}

/* @brief clearCount: send reset Frame to connecter
 *
 */
void CAN_Connecter::sendRequest(FrameSize size, uint32_t id, uint8_t dlc)
{
    canU8_t data[8];
    sendDataFrame.setMailBox(size,id,TypeRequest,dlc,data);
    char* head = (char*)sendDataFrame.head;
    serial.write(head,30);
}

/* @brief clearCount: send reset Frame to connecter
 *
 */
void CAN_Connecter::setFilter(uint8_t num, bool open, uint32_t id, uint32_t mask)
{
    sendFilterFrame.setFilter(num,open,id,mask);
    char* head = (char*)sendFilterFrame.head;
    serial.write(head,30);
}

}// namespace canCont















